home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / dskutil / 2m30src.zip / 2MUTIL.INC < prev    next >
Text File  |  1995-03-06  |  38KB  |  995 lines

  1.  
  2. ;┌───────────────────────────────────────────────────────────────────┐
  3. ;│                                                                   │
  4. ;│                  █████ █   █ █   █ █████ █████ █                  │
  5. ;│                      █ ██ ██ █   █   █     █   █                  │
  6. ;│                  █████ █ █ █ █   █   █     █   █                  │
  7. ;│                  █     █   █ █   █   █     █   █                  │
  8. ;│                  █████ █   █ █████   █   █████ █████              │
  9. ;│                                                                   │
  10. ;│                 2MUTIL  -  (C) Ciriaco García de Celis.           │
  11. ;│                                                                   │
  12. ;│      RUTINAS DE UTILIDAD EMPLEADAS DESDE DIVERSOS PROGRAMAS       │
  13. ;│                                                                   │
  14. ;└───────────────────────────────────────────────────────────────────┘
  15.  
  16. ; ------------ Extraer posibles parámetros de la línea de comandos.
  17. ;              Formato de la tabla de parámetros soportados: cinco
  18. ;              posibles modos, según el tipo de parámetro y la manera
  19. ;              de validar el rango (si es numérico). Al final de la
  20. ;              lista hay un 0. En minúsculas la parte opcional en
  21. ;              parámetros largos.
  22. ;
  23. ;              DB    "/A",0                 (caso sencillo)
  24. ;              DW    variable_booleana      (a poner a ON u OFF)
  25. ;              DB    valor_booleano         (ON u OFF)
  26. ;
  27. ;              DB    "/B",1
  28. ;              DW    min, max               (caso de /B=nn ó /B:nn)
  29. ;              DW    variable_numérica      (donde dejar nn)
  30. ;              DW    variable_booleana      (a poner a ON u OFF)
  31. ;              DB    valor_booleano         (ON u OFF)
  32. ;
  33. ;              DB    "/C",2
  34. ;              DW    numero_valores,valor1,valor2,...,valorN
  35. ;              DW    variable_numérica      (donde dejar el valor)
  36. ;              DW    variable_booleana      (a poner a ON u OFF)
  37. ;              DB    valor_booleano         (ON u OFF)
  38. ;
  39. ;              DB    "*:",3                 ( '*' = valor comodín)
  40. ;              DB    'A'                    (restar a lo que sustituye)
  41. ;              DB    max_valor              (mayor valor admitido)
  42. ;              DW    variable_dato          (y poner aquí)
  43. ;
  44. ;              DB    "D",4                  (parámetro alfanumérico)
  45. ;              DW    offset                 (offset al texto)
  46. ;
  47. ;              DB    0                      (no hay más parámetros)
  48.  
  49. obtener_param  PROC
  50.                CALL  param_mays        ; mayusculizar parámetros
  51. otro_pmt_mas:  CALL  saltar_esp        ; saltar delimitadores
  52.                JNC   otro_pmt          ; quedan más parámetros
  53.                CMP   param_ayuda,ON
  54.                JE    mal_proc_pmt      ; 'error' de ayuda
  55.                CLC                     ; parámetros bien procesados
  56.                RET
  57. mal_proc_pmt:  OR    error,ERRSINTAX   ; error en parámetro(s)
  58.                STC
  59.                RET
  60.  
  61. otro_pmt:      CALL  busca_pmt
  62.                JC    mal_proc_pmt
  63.                CMP   AL,1
  64.                JE    pmt_numerico
  65.                CMP   AL,2
  66.                JE    pmt_numerico2
  67.                CMP   AL,3
  68.                JE    pmt_comodin
  69.                CMP   AL,4
  70.                JE    pmt_alfa
  71. pmt_set:       MOV   SI,[DI]
  72.                MOV   AL,[DI+2]
  73.                MOV   [SI],AL
  74.                JMP   otro_pmt_mas
  75. pmt_numerico:  CALL  get_num
  76.                JC    mal_proc_pmt
  77.                CMP   AX,[DI]
  78.                JB    mal_proc_pmt
  79.                CMP   AX,[DI+2]
  80.                JA    mal_proc_pmt
  81. pmt_anota:     MOV   SI,[DI+4]
  82.                MOV   [SI],AX
  83.                ADD   DI,6
  84.                JMP   pmt_set
  85. pmt_numerico2: CALL  get_num
  86.                JC    mal_proc_pmt
  87.                MOV   CX,[DI]
  88. pmt_busca_r:   ADD   DI,2
  89.                MOV   SI,[DI]
  90.                CMP   AX,SI
  91.                JE    pmt_rango_ok
  92.                LOOP  pmt_busca_r
  93.                JMP   mal_proc_pmt
  94. pmt_rango_ok:  ADD   DI,2
  95.                LOOP  pmt_rango_ok
  96.                SUB   DI,4
  97.                JMP   pmt_anota
  98. pmt_comodin:   MOV   AL,ES:[BX-2]
  99.                SUB   AL,[DI]
  100.                CMP   AL,[DI+1]
  101.                JA    mal_proc_pmt
  102.                MOV   SI,[DI+2]
  103.                MOV   [SI],AL
  104.                JMP   otro_pmt_mas
  105. pmt_alfa:      MOV   SI,[DI]
  106.                INC   BX
  107.                MOV   [SI],BX
  108. saltar_asc:    MOV   AL,ES:[BX]
  109.                CMP   AL,' '
  110.                JE    fin_alfa
  111.                CMP   AL,'/'
  112.                JE    fin_alfa
  113.                CMP   AL,13
  114.                JE    fin_alfa
  115.                CMP   AL,9
  116.                JE    fin_alfa
  117.                INC   BX
  118.                JMP   saltar_asc
  119. fin_alfa:      JMP   otro_pmt_mas
  120.  
  121. busca_pmt:     MOV   DI,BP
  122. compara_pmt:   MOV   SI,BX
  123. cmp_letra:     MOV   AL,[DI]
  124.                CMP   AL,' '
  125.                JB    pmt_ahi
  126.                CMP   AL,'*'
  127.                JE    pmt_ok
  128.                CMP   AL,'a'
  129.                JAE   pmt_comod
  130. pmt_cmp:       CMP   AL,ES:[SI]
  131.                JNE   no_pmt_ahi
  132.                JMP   pmt_ok
  133. pmt_comod:     CMP   BYTE PTR ES:[SI],' '
  134.                JBE   pmt_sk
  135.                CMP   BYTE PTR ES:[SI],'/'
  136.                JE    pmt_sk
  137.                AND   AL,255-32         ; mayusculizar
  138.                JMP   pmt_cmp
  139. pmt_ok:        INC   SI
  140. pmt_sk:        INC   DI
  141.                JMP   cmp_letra
  142. pmt_ahi:       INC   DI                ; DS:DI -> info, AL = tipo
  143.                MOV   BX,SI             ; ES:BX -> siguiente parámetro
  144.                CLC
  145.                RET
  146. no_pmt_ahi:    MOV   AL,[DI]
  147.                CMP   AL,' '
  148.                JB    pmt_saltate
  149.                INC   DI
  150.                JMP   no_pmt_ahi
  151. pmt_saltate:   AND   AL,AL
  152.                JZ    pmt_salto0
  153.                CMP   AL,1
  154.                JE    pmt_salto1
  155.                CMP   AL,2
  156.                JE    pmt_salto2
  157.                CMP   AL,4
  158.                JE    pmt_salto4
  159.                ADD   DI,5
  160.                JMP   pmt_fintab?
  161. pmt_salto0:    ADD   DI,4
  162.                JMP   pmt_fintab?
  163. pmt_salto1:    ADD   DI,10
  164.                JMP   pmt_fintab?
  165. pmt_salto4:    ADD   DI,3
  166.                JMP   pmt_fintab?
  167. pmt_salto2:    MOV   AX,[DI+1]
  168.                SHL   AX,1
  169.                ADD   AX,8
  170.                ADD   DI,AX
  171. pmt_fintab?:   CMP   BYTE PTR [DI],0
  172.                JE    pmt_no_hay
  173.                JMP   compara_pmt
  174. pmt_no_hay:    STC
  175.                RET
  176. obtener_param  ENDP
  177.  
  178. ; ------------ Obtener número chequeando delimitadores /= y /:
  179.  
  180. get_num:       MOV   AL,ES:[BX]
  181.                INC   BX
  182.                CMP   AL,'='
  183.                JE    delimit_ok
  184.                CMP   AL,':'
  185.                JE    delimit_ok
  186. err_sintax:    STC                     ; sintaxis incorrecta
  187.                RET
  188. delimit_ok:    MOV   AL,ES:[BX]
  189.                XPUSH <SI, DI>
  190.                CALL  obtener_num
  191.                XPOP  <DI, SI>
  192.                JC    err_sintax
  193.                INC   BX
  194.                RET
  195.  
  196. ; ------------ Extraer nº de 16 bits y depositarlo en AX; al final, el
  197. ;              puntero (BX) apuntará al final del número y CF=1 si el
  198. ;              número era incorrecto.
  199.  
  200. obtener_num    PROC
  201.                CMP   AL,0Dh            ; fin zona parámetros y número
  202.                JE    fin_num
  203.                CMP   AL,32             ; fin número
  204.                JE    fin_num
  205.                CMP   AL,9              ; fin número
  206.                JE    fin_num
  207.                CMP   AL,'/'            ; fin número (otro parámetro)
  208.                JE    fin_num
  209.                CMP   AL,':'            ; fin número (otro dato)
  210.                JE    fin_num
  211.                INC   BX
  212.                MOV   AL,ES:[BX]
  213.                JMP   obtener_num
  214. fin_num:       MOV   SI,BX
  215.                DEC   SI
  216.                XOR   DX,DX
  217.                MOV   AX,1              ; AX = 10 elevado a la 0 = 1
  218. otro_car:      DEC   BX                ; próximo carácter a procesar
  219.                MOV   CL,ES:[BX]
  220.                CMP   CL,'='
  221.                JE    ok_num            ; delimitador: fin de número
  222.                CMP   CL,':'
  223.                JE    ok_num            ; delimitador: fin de número
  224.                CMP   CL,'.'
  225.                JNE   no_millar         ; saltar los puntos de millar
  226.                CMP   AX,1000
  227.                JE    otro_car
  228.                JMP   mal_num           ; separador millar descolocado
  229. no_millar:     CMP   CL,'0'
  230.                JB    mal_num
  231.                CMP   CL,'9'
  232.                JA    mal_num
  233.                SUB   CL,'0'            ; pasar ASCII a binario
  234.                MOV   CH,0              ; CX = 0 .. 9
  235.                PUSH  AX                ; AX = 10 elevado a la N
  236.                AND   AX,AX
  237.                JNZ   multiplica
  238.                AND   CL,CL
  239.                JNZ   mal_num_pop       ; a la izda sólo permitir ceros
  240. multiplica:    PUSH  DX                ; tras completar 5º dígito
  241.                MUL   CX
  242.                POP   DX
  243.                JC    mal_num_pop
  244.                ADD   DX,AX       ; DX = DX + digito (CX) * 10 ^ N (AX)
  245.                JC    mal_num_pop
  246.                POP   AX
  247.                CMP   AX,10000
  248.                JNE   potencia          ; AX*10 no se desbordará
  249.                MOV   AX,0              ; como próximo dígito<>0 a
  250.                JMP   otro_car          ; la izda ... pobre usuario
  251. potencia:      MOV   DI,10
  252.                PUSH  DX                ; no manchar DX al multiplicar
  253.                MUL   DI                ; AX = AX elevado a la (N+1)
  254.                POP   DX
  255.                JMP   otro_car
  256. mal_num_pop:   POP   AX                ; reequilibrar pila
  257. mal_num:       MOV   BX,SI             ; número mayor de 65535
  258.                STC                     ; condición de error
  259.                RET
  260. ok_num:        MOV   BX,SI             ; número correcto
  261.                MOV   AX,DX             ; resultado
  262.                CLC                     ; condición de Ok.
  263.                RET
  264. obtener_num    ENDP
  265.  
  266. ; ------------ Poner en mayúsculas los nombres de los parámetros.
  267.  
  268. param_mays     PROC
  269.                PUSH  BX
  270. otra_mays:     MOV   AL,ES:[BX]
  271.                CMP   AL,13
  272.                JE    mays_ret
  273.                CMP   AL,':'
  274.                JE    salta_valor
  275.                CMP   AL,'='
  276.                JE    salta_valor
  277.                JMP   mays_mas
  278. mays_ret:      POP   BX
  279.                RET
  280. mays_mas:      CMP   AL,'a'
  281.                JB    mayusc_ok
  282.                CMP   AL,'z'
  283.                JA    mayusc_ok
  284.                SUB   AL,32
  285. mayusc_ok:     MOV   ES:[BX],AL
  286.                INC   BX
  287.                JMP   otra_mays
  288. salta_valor:   INC   BX
  289.                MOV   AL,ES:[BX]
  290.                CMP   AL,' '
  291.                JE    otra_mays
  292.                CMP   AL,9
  293.                JE    otra_mays
  294.                CMP   AL,'/'
  295.                JE    otra_mays
  296.                CMP   AL,13
  297.                JE    otra_mays
  298.                JMP   salta_valor
  299. param_mays     ENDP
  300.  
  301. ; ------------ Saltar espacios, tabuladores,... buscando un parámetro.
  302.  
  303. saltar_esp:    MOV   AX,ES:[BX]
  304.                INC   BX
  305.                CMP   AL,9              ; carácter tabulador
  306.                JE    saltar_esp
  307.                CMP   AL,32             ; espacio en blanco
  308.                JE    saltar_esp
  309.                CMP   AL,0Ah            ; fin de zona de parámetros
  310.                JE    fin_param
  311.                CMP   AL,0Dh            ; fin de zona de parámetros
  312.                JE    fin_param
  313.                DEC   BX                ; puntero al primer carácter
  314.                CLC                     ; hay parámetro
  315.                RET
  316. fin_param:     STC                     ; no hay parámetro
  317.                RET
  318.  
  319. ; ------------ Comprobar si el programa ya reside en memoria. A la
  320. ;              salida, CF=0 si programa ya reside, con «tsr_seg» y
  321. ;              «tsr_off» inicializadas apuntando a la cadena de
  322. ;              identificación de la copia residente.  Si CF=1, el
  323. ;              programa no reside aún (AX=0) o reside pero en otra
  324. ;              versión distinta (AX=1).
  325.  
  326. residente?     PROC
  327.                XPUSH <CX, SI, DI, ES, AX>
  328.                LEA   DI,autor_nom_ver  ; identificación del programa
  329.                MOV   SI,DI
  330.                MOV   AL,0
  331.                MOV   CL,255
  332.                CLD
  333.                REPNE SCASB
  334.                SUB   DI,SI
  335.                MOV   CX,DI             ; tamaño autor+programa+versión
  336.                MOV   AX,1492h
  337.                MOV   ES,AX
  338.                MOV   DI,1992h          ; ES:DI protocolo de búsqueda
  339.                CALL  mx_find_tsr       ; buscar si está en memoria
  340.                MOV   tsr_off,DI        ; anotar la dirección programa
  341.                MOV   tsr_seg,ES        ; por si estaba instalado
  342.                POP   AX
  343.                JNC   resid_ok          ; CF=0 -> programa ya residente
  344.                POP   ES
  345.                PUSH  ES
  346.                LEA   DI,autor_nom_ver
  347.                MOV   SI,DI
  348.                MOV   AL,':'
  349.                MOV   CL,255
  350.                REPNE SCASB
  351.                REPNE SCASB
  352.                SUB   DI,SI
  353.                MOV   CX,DI             ; tamaño autor+programa
  354.                MOV   AX,1492h
  355.                MOV   ES,AX
  356.                MOV   DI,1992h          ; ES:DI protocolo de búsqueda
  357.                CALL  mx_find_tsr       ; buscar si está en memoria
  358.                MOV   tsr_off,DI        ; anotar dirección del programa
  359.                MOV   tsr_seg,ES        ; por si instalada otra versión
  360.                MOV   AX,0
  361.                JC    resid_ok          ; CF=1, AX=0 -> no residente
  362.                MOV   AX,1
  363.                STC                     ; CF=1, AX=1 -> sí: otra vers.
  364. resid_ok:      XPOP  <ES, DI, SI, CX>
  365.                RET
  366. residente?     ENDP
  367.  
  368. ; ------------ Considerar presencia de controlador XMS.
  369.  
  370. inic_XMS       PROC
  371.                PUSH  ES
  372.                MOV   AX,352Fh
  373.                INT   21h               ; dirección de INT 2Fh en ES:BX
  374.                MOV   AX,ES
  375.                POP   ES
  376.                AND   AX,AX
  377.                JZ    xms_ausente       ; apunta a 0000:XXXX (DOS 2.x)
  378.                MOV   AX,4300h
  379.                INT   2Fh               ; chequear presencia XMS
  380.                CMP   AL,80h
  381.                JNE   XMS_ausente       ; no instalado
  382.                PUSH  ES
  383.                MOV   AX,4310h
  384.                INT   2Fh               ; sí: obtener su dirección
  385.                MOV   XMS_off,BX        ; y preservarla
  386.                MOV   XMS_seg,ES
  387.                MOV   xms_ins,ON
  388.                POP   ES
  389.                RET
  390. XMS_ausente:   MOV   xms_ins,OFF
  391.                RET
  392. inic_XMS       ENDP
  393.  
  394. ; ------------ Preservar vectores de interrupción previos.
  395.  
  396. preservar_INTs PROC
  397.                XPUSH <ES, DI>
  398.                LEA   DI,tabla_vectores
  399.                MOV   CL,[DI-1]
  400.                MOV   CH,0              ; CX vectores interceptados
  401. otro_vector:   XPUSH <CX, DI>
  402.                MOV   AH,35h
  403.                MOV   AL,[DI]
  404.                INT   21h               ; obtener vector de INT xx
  405.                XPOP  <DI, CX>
  406.                MOV   [DI+1],BX         ; anotar donde apunta
  407.                MOV   [DI+3],ES
  408.                ADD   DI,5
  409.                LOOP  otro_vector       ; repetir con los restantes
  410.                XPOP  <DI, ES>
  411.                RET
  412. preservar_INTs ENDP
  413.  
  414. ; ------------ Liberar espacio de entorno.
  415.  
  416. free_environ   PROC
  417.                PUSH  ES
  418.                MOV   ES,DS:[2Ch]       ; dirección del entorno
  419.                MOV   AH,49h
  420.                INT   21h               ; liberar espacio de entorno
  421.                POP   ES
  422.                RET
  423. free_environ   ENDP
  424.  
  425. ; ------------ Reservar bloque de memoria superior del nº párrafos AX,
  426. ;              devolviendo en AX el segmento donde está. CF=1 si no
  427. ;              está instalado el gestor XMS (AX=0) o hay un error (AL
  428. ;              devuelve el código de error del controlador XMS).
  429.  
  430. UMB_alloc      PROC
  431.                XPUSH <BX, CX, DX>
  432.                CMP   xms_ins,ON
  433.                JNE   no_umb_disp       ; no hay controlador XMS
  434.                MOV   DX,AX             ; número de párrafos
  435.                MOV   AH,10h            ; solicitar memoria superior
  436.                CALL  gestor_XMS
  437.                CMP   AX,1              ; ¿ha ido todo bien?
  438.                MOV   AX,BX             ; segmento UMB/código de error
  439.                JNE   XMS_fallo         ; fallo
  440.                XPOP  <DX, CX, BX>      ; ok
  441.                CLC
  442.                RET
  443. no_umb_disp:   MOV   AX,0
  444. XMS_fallo:     XPOP  <DX, CX, BX>
  445.                STC
  446.                RET
  447. UMB_alloc      ENDP
  448.  
  449. ; ------------ Reservar memoria superior, con DOS 5.0, del tamaño
  450. ;              solicitado (AX párrafos). Si no hay bastante CF=1,
  451. ;              en caso contrario devuelve el segmento en AX.
  452.  
  453. UPPER_alloc    PROC
  454.                PUSH  AX
  455.                MOV   AH,30h
  456.                INT   21h
  457.                CMP   AL,5
  458.                POP   AX
  459.                JAE   UPPER_existe
  460.                STC
  461.                JMP   UPPER_fin         ; necesario DOS 5.0 mínimo
  462. UPPER_existe:  PUSH  AX                ; preservar párrafos...
  463.                MOV   AX,5800h
  464.                INT   21h
  465.                MOV   alloc_strat,AX    ; preservar estrategia
  466.                MOV   AX,5802h
  467.                INT   21h
  468.                MOV   umb_state,AL      ; preservar estado UMB
  469.                MOV   AX,5803h
  470.                MOV   BX,1
  471.                INT   21h               ; conectar cadena UMB's
  472.                MOV   AX,5801h
  473.                MOV   BX,41h
  474.                INT   21h               ; High Memory best fit
  475.                POP   BX                ; ...párrafos requeridos
  476.                MOV   AH,48h
  477.                INT   21h               ; asignar memoria
  478.                PUSHF
  479.                PUSH  AX                ; guardado el resultado
  480.                MOV   AX,5801h
  481.                MOV   BX,alloc_strat
  482.                INT   21h               ; restaurar estrategia
  483.                MOV   AX,5803h
  484.                MOV   BL,umb_state
  485.                XOR   BH,BH
  486.                INT   21h               ; restaurar estado cadena UMB
  487.                POP   AX
  488.                POPF
  489. upper_fin:     RET
  490. UPPER_alloc    ENDP
  491.  
  492. ; ------------ Manipular PID para independizar el bloque de memoria
  493. ;              superior del programa y dejarlo residente. ES apunta
  494. ;              al segmento y DS al PSP del programa principal.
  495.  
  496. upper_fork     PROC
  497.                XPUSH <AX, CX, SI, DI, DS, ES>
  498.                MOV   AX,ES
  499.                DEC   AX
  500.                MOV   ES,AX
  501.                INC   AX
  502.                MOV   WORD PTR ES:[1],AX      ; manipular PID
  503.                MOV   WORD PTR ES:[16],20CDh  ; simular PSP
  504.                MOV   AX,DS
  505.                DEC   AX
  506.                MOV   DS,AX
  507.                MOV   CX,8
  508.                MOV   SI,CX
  509.                MOV   DI,CX
  510.                CLD
  511.                REP   MOVSB             ; copiar nombre de programa
  512.                XPOP  <ES, DS, DI, SI, CX, AX>
  513.                RET
  514. upper_fork     ENDP
  515.  
  516. ; ------------ Reubicar programa residente a su dirección definitiva.
  517. ;              A la entrada, párrafos a mover en CX.
  518.  
  519. reubicar_prog  PROC
  520.                PUSH  DI
  521.                LEA   SI,ini_residente
  522.                SHL   CX,1
  523.                SHL   CX,1
  524.                SHL   CX,1
  525.                SHL   CX,1
  526.                CLD
  527.                ADD   SI,2              ; no copiar primera palabra
  528.                ADD   DI,2              ; respetar primera palabra
  529.                SUB   CX,2
  530.                REP   MOVSB
  531.                POP   DI
  532.                RET
  533. reubicar_prog  ENDP
  534.  
  535. ; ------------ desviar vectores de interrupción a las nuevas rutinas.
  536. ;              Se tendrá en cuenta que está ensambladas para correr en
  537. ;              un offset inicial (100h) y que el offset real en que
  538. ;              han sido instaladas está en DI. Por ello, CS ha de
  539. ;              desplazarse (100h-DI)/16 unidades atrás (DI se supone
  540. ;              múltiplo de 16). El segmento inicial es ES.
  541.  
  542. activar_INTs   PROC
  543.                XPUSH <CX, DS>          ; preservar DS para el retorno
  544.                MOV   AX,100h
  545.                SUB   AX,DI             ; AX = 100h-DI
  546.                MOV   CL,4
  547.                SHR   AX,CL             ; AX = (100h-DI)/16
  548.                MOV   CX,ES
  549.                SUB   CX,AX
  550.                MOV   tsr_seg,CX
  551.                MOV   DS,CX
  552.                LEA   SI,offsets_ints
  553.                MOV   CX,CS:[SI]        ; CX vectores a desviar
  554.                ADD   SI,2
  555. desvia_otro:   MOV   AL,CS:[SI]        ; número del vector en curso
  556.                MOV   DX,CS:[SI+1]      ; obtener offset
  557.                MOV   AH,25h
  558.                INT   21h               ; desviar INT xx a DS:DX
  559.                ADD   SI,3
  560.                LOOP  desvia_otro
  561.                XPOP  <DS, CX>
  562.                RET
  563. activar_INTs   ENDP
  564.  
  565. ; ------------ Buscar entrada no usada en la interrupción Multiplex.
  566. ;              A la salida, CF=1 si no hay hueco (ya hay 64 programas
  567. ;              residentes instalados con esta técnica). Si CF=0, se
  568. ;              devuelve en AH un valor de entrada libre en la INT 2Fh.
  569.  
  570. mx_get_handle  PROC
  571.                MOV   AH,0C1h
  572. mx_busca_hndl: PUSH  AX
  573.                MOV   AL,0
  574.                INT   2Fh
  575.                CMP   AL,0FFh
  576.                POP   AX
  577.                JNE   mx_si_hueco
  578.                INC   AH
  579.                JNZ   mx_busca_hndl
  580.                STC
  581.                RET
  582. mx_si_hueco:   CLC
  583.                RET
  584. mx_get_handle  ENDP
  585.  
  586. ; ------------ Buscar un TSR por la interrupción Multiplex. A la
  587. ;              entrada, DS:SI cadena de identificación del programa
  588. ;              (CX bytes) y ES:DI protocolo de búsqueda (normalmente
  589. ;              1492h:1992h). A la salida, si el TSR ya está instalado,
  590. ;              CF=0 y ES:DI apunta a la cadena de identificación del
  591. ;              mismo. Si no, CF=1 y ningún registro alterado.
  592.  
  593. mx_find_tsr    PROC
  594.                MOV   AH,0C1h
  595. mx_rep_find:   XPUSH <AX, CX, SI, DS, ES, DI>
  596.                MOV   AL,0
  597.                PUSH  CX
  598.                INT   2Fh
  599.                POP   CX
  600.                CMP   AL,0FFh
  601.                JNE   mx_skip_hndl      ; no hay TSR ahí
  602.                CLD
  603.                PUSH  DI
  604.                REP   CMPSB             ; comparar identificación
  605.                POP   DI
  606.                JE    mx_tsr_found      ; programa buscado hallado
  607. mx_skip_hndl:  XPOP  <DI, ES, DS, SI, CX, AX>
  608.                INC   AH
  609.                JNZ   mx_rep_find
  610.                STC
  611.                RET
  612. mx_tsr_found:  ADD   SP,4              ; «sacar» ES y DI de la pila
  613.                XPOP  <DS, SI, CX, AX>
  614.                CLC
  615.                RET
  616. mx_find_tsr    ENDP
  617.  
  618. ; ------------ Eliminar TSR del convenio si es posible. A la entrada,
  619. ;              en AH se indica la entrada Multiplex; a la salida, CF=1
  620. ;              si fue imposible y CF=0 si se pudo. Se corrompen todos
  621. ;              los registros salvo los de segmento. En caso de fallo
  622. ;              al desinstalar, AL devuelve el vector «culpable».
  623.  
  624. mx_unload      PROC
  625.                PUSH  ES
  626.                CALL  mx_ul_tsrcv?
  627.                JNC   mx_ul_able
  628.                POP   ES
  629.                RET
  630. mx_ul_able:    XOR   AL,AL
  631.                XCHG  AH,AL
  632.                MOV   BP,AX             ; BP=entrada Multiplex del TSR
  633.                MOV   CX,2
  634. mx_ul_pasada:  PUSH  CX                ; siguiente pasada
  635.                LEA   SI,tabla_vectores
  636.                MOV   CL,ES:[SI-1]
  637.                MOV   CH,0              ; CX = nº vectores
  638. mx_ul_masvect: POP   AX
  639.                PUSH  AX                ; pasada en curso
  640.                DEC   AL
  641.                PUSH  CX
  642. mx_ul_2f:      MOV   AL,ES:[SI]        ; vector en curso
  643.                JNZ   mx_ul_pasok
  644.                CMP   CX,1              ; ¿último vector?
  645.                JNE   mx_ul_noult
  646.                MOV   AL,2Fh
  647.                LEA   SI,tabla_vectores
  648. mx_ul_busca2f: CMP   ES:[SI],AL        ; ¿INT 2Fh?
  649.                JE    mx_ul_pasok
  650.                ADD   SI,5
  651.                JMP   mx_ul_busca2f
  652. mx_ul_noult:   CMP   AL,2Fh            ; ¿restaurar INT 2Fh?
  653.                JNE   mx_ul_pasok
  654.                ADD   SI,5
  655.                JMP   mx_ul_2f
  656. mx_ul_pasok:   XPUSH <ES, AX>
  657.                MOV   AH,0
  658.                SHL   AX,1
  659.                SHL   AX,1
  660.                DEC   AX
  661.                MOV   CS:mx_ul_tsroff,AX
  662.                MOV   CS:mx_ul_tsrseg,0 ; apuntar a tabla vectores
  663.                POP   AX
  664.                PUSH  AX
  665.                MOV   AH,35h
  666.                INT   21h               ; vector en ES:BX
  667.                POP   AX
  668.                MOV   CL,4
  669.                SHR   BX,CL
  670.                MOV   DX,ES
  671.                ADD   DX,BX             ; INT xx en DX (aprox.)
  672.                MOV   AH,0C1h
  673. mx_ul_masmx:   CALL  mx_ul_tsrcv?
  674.                JNC   mx_ul_tsrcv
  675.                JMP   mx_ul_otro
  676. mx_ul_tsrcv:   PUSH  ES:[DI-16]        ; ...TSR del convenio en ES:DI
  677.                PUSH  ES:[DI-12]
  678.                MOV   DI,ES:[DI-8]      ; offset a la tabla de vectores
  679.                MOV   CL,ES:[DI-1]
  680.                MOV   CH,0              ; número de vectores en CX
  681. mx_ul_buscav:  CMP   AL,ES:[DI]
  682.                JE    mx_ul_usavect     ; este TSR usa vector analizado
  683.                ADD   DI,5
  684.                LOOP  mx_ul_buscav
  685.                ADD   SP,4              ; no lo usa
  686.                JMP   mx_ul_otro
  687. mx_ul_usavect: XPOP  <CX, BX>          ; tamaño y segmento del TSR
  688.                CMP   DX,BX
  689.                JB    mx_ul_otro        ; la INT xx no le apunta
  690.                ADD   BX,CX
  691.                CMP   DX,BX
  692.                JA    mx_ul_otro        ; la INT xx le apunta
  693.                PUSH  AX
  694.                XOR   AL,AL
  695.                XCHG  AH,AL
  696.                CMP   AX,BP             ; ¿es el propio TSR?
  697.                POP   AX
  698.                JNE   mx_ul_chain       ; no
  699.                XPOP  <ES, CX, BX>      ; sí: ¡posible reponer vector!
  700.                XPUSH <BX, CX, ES>
  701.                DEC   BX
  702.                JNZ   mx_ul_norest      ; no es la segunda pasada
  703.                POP   ES                ; segunda pasada...
  704.                XPUSH <ES, DS>
  705.                MOV   BX,CS:mx_ul_tsroff ; restaurar INT's
  706.                MOV   DS,CS:mx_ul_tsrseg
  707.                CLI
  708.                MOV   CX,ES:[SI+1]
  709.                MOV   [BX+1],CX
  710.                MOV   CX,ES:[SI+3]
  711.                MOV   [BX+3],CX
  712.                STI
  713.                POP   DS
  714. mx_ul_norest:  XPOP  <ES, CX>
  715.                ADD   SI,5              ; siguiente vector
  716.                DEC   CX
  717.                JZ    mx_unloadable     ; no más, ¡desinstal-ar/ado!
  718.                JMP   mx_ul_masvect
  719. mx_ul_chain:   MOV   CS:mx_ul_tsroff,DI ; ES:DI almacena la dirección
  720.                MOV   CS:mx_ul_tsrseg,ES ; de la variable vector
  721.                MOV   DX,ES:[DI+1]
  722.                MOV   CL,4
  723.                SHR   DX,CL
  724.                MOV   CX,ES:[DI+3]
  725.                ADD   DX,CX             ; INT xx en DX (aprox.)
  726.                MOV   AH,0BFh
  727. mx_ul_otro:    INC   AH                ; a por otro TSR
  728.                JZ    mx_ul_exitnok     ; ¡se acabaron!
  729.                JMP   mx_ul_masmx
  730. mx_ul_exitnok: ADD   SP,6              ; equilibrar pila
  731.                POP   ES
  732.                STC
  733.                RET                     ; imposible desinstalar
  734. mx_unloadable: POP   CX
  735.                DEC   CX
  736.                JZ    mx_ul_exitok      ; desinstalado
  737.                JMP   mx_ul_pasada      ; 1ª pasada exitosa: por la 2ª
  738. mx_ul_exitok:  TEST  ES:info_extra,111b  ; ¿tipo de instalación?
  739.                MOV   ES,ES:segmento_real ; segmento real del bloque
  740.                JZ    mx_ul_freeml        ; cargado en RAM convencional
  741.                CMP   xms_ins,ON
  742.                JNE   mx_ul_freeml      ; no hay controlador XMS (¿?)
  743.                MOV   DX,ES
  744.                MOV   AH,11h
  745.                CALL  gestor_XMS        ; liberar memoria superior
  746.                POP   ES
  747.                CLC
  748.                RET
  749. mx_ul_freeml:  MOV   AH,49h
  750.                INT   21h               ; liberar bloque de memoria ES:
  751.                POP   ES
  752.                CLC
  753.                RET
  754. mx_ul_tsrcv?:  XPUSH <AX, ES, DI>       ; ¿es TSR del convenio?...
  755.                MOV   DI,1492h
  756.                MOV   ES,DI
  757.                MOV   DI,1992h
  758.                INT   2Fh
  759.                CMP   AX,0FFFFh
  760.                JNE   mx_ul_ncvexit
  761.                CMP   WORD PTR ES:[DI-4],"#*"
  762.                JNE   mx_ul_ncvexit
  763.                CMP   WORD PTR ES:[DI-2],"*#"
  764.                JNE   mx_ul_ncvexit
  765.                ADD   SP,4              ; CF=0
  766.                POP   AX
  767.                RET
  768. mx_ul_ncvexit: XPOP  <DI, ES, AX>      ; ...no es TSR del convenio
  769.                STC                     ; CF=1
  770.                RET
  771. mx_ul_tsroff   DW    0
  772. mx_ul_tsrseg   DW    0
  773. mx_unload      ENDP
  774.  
  775. ; ------------ Devolver tipo de la unidad DL en BL, CF=1 si error.
  776. ;              Se tiene especial cuidado con lo que devuelve la
  777. ;              función (registros que modifica) y se reintenta porque
  778. ;              algunas BIOS Award devuelven el error 6 (cambio de
  779. ;              disco) al primer acceso, incluso ¡en esta función!.
  780.  
  781. tipo_disco     PROC
  782.                XPUSH <AX, CX, DI, ES>  ; *
  783.                MOV   CX,3
  784. busc_tipo:     XPUSH <CX, DX>          ; ** 3 reintentos
  785.                MOV   AH,8
  786.                MOV   BL,0
  787.                INT   13h
  788.                JC    tipo_dsk_err
  789.                AND   BL,BL
  790.                JZ    tipo_dsk_err
  791.                AND   DL,DL
  792.                JZ    tipo_dsk_err
  793.                CMP   BL,4
  794.                JBE   tipo_dsk_ok
  795.                MOV   BL,5                ; código 5 para 2.88M
  796. tipo_dsk_ok:   XPOP  <DX, CX>            ; **1
  797.                XPOP  <ES, DI, CX, AX>    ; *1
  798.                CLC
  799.                RET
  800. tipo_dsk_err:  XPOP  <DX, CX>            ; **2
  801.                LOOP  busc_tipo
  802.                MOV   BL,0
  803.                XPOP  <ES, DI, CX, AX>    ; *2
  804.                STC
  805.                RET
  806. tipo_disco     ENDP
  807.  
  808. ; ------------ Establecer el tipo de las unidades a nivel DOS.
  809. ;              A la entrada, DI apunta a la tabla de definiciones.
  810.  
  811. set_dev_params PROC
  812.                MOV   AH,30h
  813.                INT   21h
  814.                XCHG  AH,AL
  815.                CMP   AX,314h
  816.                JB    dev_set           ; DOS < 3.2 -> no soportado
  817.                MOV   BX,1
  818. set_otro_dev:  PUSH  BX
  819.                MOV   AH,8
  820.                MOV   DL,BL
  821.                DEC   DL
  822.                PUSH  BX
  823.                PUSH  ES
  824.                PUSH  DI
  825.                INT   13h               ; obtener tipo de la unidad
  826.                POP   DI
  827.                POP   ES
  828.                MOV   BH,0
  829.                SHL   BX,1
  830.                MOV   DX,[BX+DI]        ; DS:DX -> tabla de información
  831.                POP   BX
  832.                AND   DX,DX
  833.                JZ    device_set
  834.                MOV   AX,440Dh          ; IOCTL
  835.                MOV   CX,0840h
  836.                PUSH  DI
  837.                INT   21h               ; establecer tipo de soporte
  838.                POP   DI
  839. device_set:    POP   BX
  840.                INC   BX
  841.                CMP   BX,2
  842.                JBE   set_otro_dev
  843. dev_set:       RET
  844. set_dev_params ENDP
  845.  
  846. ; ------------ Inicializar variable idioma_sp según idioma del país.
  847.  
  848. habla_hispana? PROC
  849.                XPUSH <AX, BX, CX, DX, BP>
  850.                MOV   AH,30h
  851.                INT   21h
  852.                XCHG  AH,AL             ; AX = versión del DOS
  853.                MOV   BP,AX
  854.                MOV   idioma_sp,OFF     ; supuesto de habla no hispana
  855.                CMP   BP,200h
  856.                JB    habla_ok
  857.                LEA   DX,buffer_aux
  858.                MOV   AX,3800h
  859.                INT   21h               ; obtener información del pais
  860.                CMP   BP,20Bh
  861.                JE    habla_ax          ; DOS 2.11: AX cód. telefónico
  862.                CMP   BP,300h
  863.                JB    habla_ok          ; 2.x excepto 2.11: mala suerte
  864.                MOV   AX,BX
  865. habla_ax:      LEA   BX,paises_sp-2
  866.                MOV   CX,numpaises_sp
  867. habla_sp?:     ADD   BX,2
  868.                CMP   AX,[BX]
  869.                JE    habla_hispana
  870.                LOOP  habla_sp?
  871. habla_ok:      MOV   AL,param_i
  872.                XOR   idioma_sp,AL      ; considerar parámetro /I
  873.                XPOP  <BP, DX, CX, BX, AX>
  874.                RET
  875. habla_hispana: MOV   idioma_sp,ON      ; país de habla hispana
  876.                MOV   AL,param_i
  877.                XOR   idioma_sp,AL      ; considerar parámetro /I
  878.                XPOP  <BP, DX, CX, BX, AX>
  879.                RET
  880. habla_hispana? ENDP
  881.  
  882. ; ------------ Imprimir cadena en DS:DX delimitada por un 0 ó un 255.
  883. ;              Si hay que imprimir en inglés se toma la cadena que va
  884. ;              después si ésta acaba en 255 (si acaba en 0, no hay
  885. ;              distinción entre mensaje castellano e inglés). El
  886. ;              carácter de control 1 realiza una pausa hasta que se
  887. ;              pulsa una tecla.
  888.  
  889. print          PROC
  890.                XPUSH <AX, BX, CX, DX>
  891. pr_decidir:    CMP   idioma_sp,OFF
  892.                JE    usar_uk
  893.                CMP   idioma_sp,ON
  894.                JE    usar_sp
  895.                PUSH  DX
  896.                CALL  habla_hispana?         ; determinar lengua
  897.                POP   DX
  898.                JMP   pr_decidir
  899. usar_uk:       MOV   BX,DX
  900.                DEC   BX
  901. usar_uk?:      INC   BX
  902.                CMP   BYTE PTR [BX],0
  903.                JE    usar_sp                ; acaba en 0: no traducir
  904.                CMP   BYTE PTR [BX],255
  905.                JNE   usar_uk?
  906.                LEA   DX,[BX+1]              ; acaba en 255: traducir
  907. usar_sp:       MOV   BX,DX
  908.                DEC   BX
  909. print_cad:     INC   BX
  910.                CMP   BYTE PTR [BX],0
  911.                JE    prlong_ok
  912.                CMP   BYTE PTR [BX],1        ; carácter de pausa
  913.                JE    prpausa
  914.                CMP   BYTE PTR [BX],255
  915.                JNE   print_cad              ; calcular longitud
  916.                JMP   prlong_ok
  917. prpausa:       PUSH  BX
  918.                MOV   CX,BX
  919.                SUB   CX,DX
  920.                MOV   AH,40h
  921.                MOV   BX,1
  922.                INT   21h               ; imprimir hasta el código 1
  923. pr_limpbuf:    MOV   AH,1
  924.                INT   16h
  925.                JZ    pr_notec
  926.                MOV   AH,0
  927.                INT   16h               ; limpiar buffer del teclado
  928.                JMP   pr_limpbuf
  929. pr_notec:      MOV   AH,0
  930.                INT   16h               ; esperar tecla
  931.                POP   BX
  932.                INC   BX
  933.                MOV   DX,BX
  934.                CMP   AL,27             ; ¿tecla ESC?
  935.                STC
  936.                JE    pr_ret
  937.                JMP   print_cad         ; imprimir el resto
  938. prlong_ok:     MOV   CX,BX
  939.                SUB   CX,DX
  940.                MOV   AH,40h
  941.                MOV   BX,1
  942.                INT   21h
  943.                CLC
  944. pr_ret:        XPOP  <DX, CX, BX, AX>  ; CF = 1 si ESC durante pausa
  945.                RET
  946. print          ENDP
  947.  
  948. ; ------------ Variables para estas subrutinas.
  949.  
  950. xms_ins        DB    OFF       ; a ON si presente controlador XMS
  951. gestor_XMS     LABEL DWORD     ; dirección del controlador XMS
  952. XMS_off        DW    0
  953. XMS_seg        DW    0
  954.  
  955. parrafos_resid DW    ?         ; párrafos de memoria consumidos
  956. alloc_strat    DW    0         ; estrategia asignación (DOS 5)
  957. umb_state      DB    0         ; estado de bloques UMB (DOS 5)
  958.  
  959. tsr_dir        LABEL DWORD     ; dirección de la copia residente
  960. tsr_off        DW    0
  961. tsr_seg        DW    0
  962.  
  963. mem640         DW    0         ; párrafos de memoria convencional
  964.  
  965. param_i        DB    OFF       ; supuesto que no hay parámetro /I
  966.  
  967. idioma_sp      DB    5Ah       ; ni en ON ni en OFF al principio
  968.  
  969.                ; --- Código telefónico de países de
  970.                ;     habla hispana (mucha o poca).
  971.  
  972. paises_sp      DW    54                ; Argentina
  973.                DW    591               ; Bolivia
  974.                DW    57                ; Colombia
  975.                DW    506               ; Costa Rica
  976.                DW    56                ; Chile
  977.                DW    593               ; Ecuador
  978.                DW    503               ; El Salvador
  979.                DW    34                ; España
  980.                DW    63                ; Filipinas
  981.                DW    502               ; Guatemala
  982.                DW    504               ; Honduras
  983.                DW    212               ; Marruecos
  984.                DW    52                ; México
  985.                DW    505               ; Nicaragua
  986.                DW    507               ; Panamá
  987.                DW    595               ; Paraguay
  988.                DW    51                ; Perú
  989.                DW    80                ; Puerto Rico
  990.                DW    508               ; República Dominicana
  991.                DW    598               ; Uruguay
  992.                DW    58                ; Venezuela
  993.                DW    3                 ; genérico latinoamérica
  994. numpaises_sp   EQU   ($-OFFSET paises_sp)/2
  995.